// TextRenderer.cpp
//
#include "TextRenderer.h"

#include "OpenGL.h"
#include "Font.h"
#include "Renderer.h"

using namespace OpenGL;

// ------------------------------------------------------------------------------------------------
TextRenderer::TextRenderer( Renderer *r )
: _renderer(r)
{}

// ------------------------------------------------------------------------------------------------
TextRenderer::~TextRenderer()
{}

// ------------------------------------------------------------------------------------------------
void TextRenderer::addTag( const TextTag &tag )
{
	if( !tag._text.empty() )
		_tags.push_back(tag);
}

// ------------------------------------------------------------------------------------------------
bool TextRenderer::isEmpty() const
{
	return _tags.empty();
}

// ------------------------------------------------------------------------------------------------
void TextRenderer::draw()
{
	if( _tags.empty() )
		return;

	Font *f = _renderer->getFont();

	if( !f )
		return;

	f->bind();

	const Math::dmat4 pm = _renderer->projectionMatrix();
	const Math::dmat4 mm = _renderer->modelViewMatrix();

	_renderer->setScreenSpaceProjection();
	_renderer->setModelView( Math::dmat4(1) );

	glPushAttrib( GL_COLOR_BUFFER_BIT );
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);


	for( std::list<TextTag>::iterator jt = _tags.begin();
		 jt != _tags.end();
		 ++jt )
	{
		//std::list<TextTag>::iterator jt = it++;
		if( jt->_visible )
		{
			glColor4fv( jt->_color );

			glPushMatrix();
			glTranslated( jt->_screenPos.x, jt->_screenPos.y, jt->_screenPos.z );
			
			f->pushSize();
			f->setSize( jt->_size );
			f->drawText( jt->_text );
			f->popSize();
			glPopMatrix();

#if 0
			// debug Box
			glDisable(GL_TEXTURE_2D);
			glColor4f(0,0,1,1);
			glBegin( GL_LINE_LOOP );
				glVertex2d( jt->_box.minPoint().x, jt->_box.minPoint().y );
				glVertex2d( jt->_box.maxPoint().x, jt->_box.minPoint().y );
				glVertex2d( jt->_box.maxPoint().x, jt->_box.maxPoint().y );
				glVertex2d( jt->_box.minPoint().x, jt->_box.maxPoint().y );
			glEnd();
			glEnable(GL_TEXTURE_2D);
#endif
		}

		//_tags.erase(jt);
	}

	glPopAttrib();
	_tags.clear();

	f->unbind();

	_renderer->setProjection(pm);
	_renderer->setModelView(mm);
}

// ------------------------------------------------------------------------------------------------
void TextRenderer::update()
{
	Font *f = _renderer->getFont();

	std::vector< TextTag* > lbl;
	
	const Math::ivec4 vp = _renderer->viewport();
	Math::box3  vb( Math::dvec3(vp.x,vp.y,0.0),Math::dvec3(vp.z,vp.w,0.0) );

	_box = Math::box3();

	for( std::list<TextTag>::reverse_iterator it = _tags.rbegin();
		 it != _tags.rend();
		 ++it )
	{
		// compute overlapping with other tags
		const double strH = f->getHeight();
		const double strW = f->getTextWidth(it->_text,it->_size,false);
		Math::dvec3 p0( 0.0, strH, 0.0 );
		Math::dvec3 p1( strW, 0.0, 0.0 );

		double xOffset = 0.0;

		switch( it->_alignment )
		{
		case TextRenderer::AlignRight:		xOffset = -strW*1.0; break;
		case TextRenderer::AlignCenter:     xOffset = -strW*0.5; break;
		case TextRenderer::AlignLeft:		break;	
		}

		const Math::dvec3 offset(xOffset,0,0);
		const Math::dvec3 p = _renderer->convertWorldToWindow( it->_worldPos,false );

		it->_screenPos = p+offset;
		it->_box       = Math::box3::createAABB( it->_screenPos-p0, it->_screenPos+p1 );

		// the first is always visible
		if( lbl.empty() )
		{
			it->_visible = true;
			lbl.push_back(&(*it));
		}
		else
		{
			// tag is visible if not overlaps other tags
			for( size_t j=0; j<lbl.size(); ++j )
			{
				it->_visible = true;
				if( lbl[j]->_box.overlaps2D(it->_box) )
				{
					it->_visible = false;
					break;
				}
			}

			// add to the visibles list
			if(it->_visible)
			{
				lbl.push_back( &(*it) );
				//const Math::dvec2 minP = _renderer->convertWindowTo2D( it->_box.minPoint().x,it->_box.minPoint().y,false );
				//const Math::dvec2 maxP = _renderer->convertWindowTo2D( it->_box.maxPoint().x,it->_box.maxPoint().y,false );

				//_box.extend( Math::box3( Math::dvec3(minP,0), Math::dvec3(maxP,0) ) );
			}
		}

		// eventually cull not visible tags
		if( it->_visible && !vb.contains2D(it->_box) && !vb.overlaps2D(it->_box) )
			it->_visible = false;		
	}
}

